import 'dart:async';
import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';
import 'package:stack_trace/stack_trace.dart';
import 'package:universal_io/io.dart';

import '../../config.dart';
import '../../ui/widget/my_text.dart';

enum LogLevel {
  OFF,
  FATAL,
  ERROR,
  WARN,
  INFO,
  DEBUG,
  ALL,
}

String logStr = "";
bool logUpdate = false;

const ERROR_TAG = "\x1B[31m[ERROR]\x1B[0m";
const WARN_TAG = "\x1B[33m[WARN]\x1B[0m";

void logi(String tag, Object object) {
  if (JmConfig.logLevel.index < LogLevel.INFO.index) {
    return;
  }
  Jm_log.i(tag, object);
  logUpdate = true;
}

void logd(String tag, Object? object, {bool stack = false}) {
  if (JmConfig.logLevel.index < LogLevel.DEBUG.index) {
    return;
  }
  Jm_log.d(tag, object, stack: stack);
  logUpdate = true;
}

void logw(String tag, Object object) {
  if (JmConfig.logLevel.index < LogLevel.WARN.index) {
    return;
  }
  Jm_log.w(tag, object);
  logUpdate = true;
}

void loge(String tag, Object object) {
  //Jm_log.e(tag, object);
  if (JmConfig.logLevel.index < LogLevel.ERROR.index) {
    return;
  }
  Jm_log.e(tag, object);
  logUpdate = true;
}

void loget(String tag, Object object, {StackTrace? stackTrace}) {
  //Jm_log.e(tag, object);
  if (JmConfig.logLevel.index < LogLevel.ERROR.index) {
    return;
  }
  Jm_log.et(tag, object, stackTrace: stackTrace);
  logUpdate = true;
}

void logf(String tag, Object object) {
  //Jm_log.e(tag, object);
  if (JmConfig.logLevel.index < LogLevel.FATAL.index) {
    return;
  }
  Jm_log.e(tag, object);
  logUpdate = true;
}

String nowTimeStr() {
  DateTime now = DateTime.now();
  return formatDate(now, [HH, ':', nn, ':', ss, ".", SSS]);
  //return formatDate(DateTime.now(), [yyyy, '-', mm, '-', dd, " ",HH, ':', nn, ':', ss, ".", uuu]);
}

class Jm_log {
  static void d(String tag, Object? object,
      {bool stack = false, bool time = true}) {
    String str;
    String timeStr = "";
    String objectStr = "";

    if (time) {
      timeStr = nowTimeStr();
    }

    if (object == null) {
      objectStr = "null";
    } else {
      objectStr = object.toString();
    }

    if (stack) {
      String trace = Trace.current().frames[2].location;
      str = "$timeStr [$tag] $trace $objectStr";
    } else {
      str = "$timeStr [$tag] $objectStr";
    }

    logStr += str + "\n";
    if (Platform.isAndroid) {
      print("\x1B[34m$str\x1B[0m");
    } else {
      print(str);
    }
  }

  static void i(String tag, Object object) {
    String str = "[$tag] $object";
    logStr += str + "\n";

    if (Platform.isAndroid) {
      print("\x1B[32m$str\x1B[0m");
    } else {
      print(str);
    }
  }

  static void w(String tag, Object object) {
    String timeStr = "";

    //if(time){
    timeStr = nowTimeStr();
    //}
    String str = "▷ $timeStr [$tag] $object";
    logStr += str + "\n";

    if (Platform.isAndroid) {
      print("\x1B[33m$str\x1B[0m");
    } else {
      print(str);
    }
  }

  static void et(String tag, Object object, {StackTrace? stackTrace}) {
    String timeStr = "";

    //if(time){
    timeStr = nowTimeStr();
    String trace = "";
    if (stackTrace != null) {
      trace = stackTrace.toString();
    }

    String str = "▶ $timeStr [$tag] $object $trace";
    logStr += str + "\n";

    if (Platform.isAndroid) {
      print("\x1B[33m$str\x1B[0m");
    } else {
      print(str);
    }
  }

  static void e(String tag, Object object, {bool time = true}) {
    String trace = Trace.current().frames[2].location;
    String timeStr = "";

    if (time) {
      timeStr = nowTimeStr();
    }
    String str = "$timeStr ▶ [$tag] $trace $object";
    logStr += str + "\n";

    if (Platform.isAndroid) {
      print("\x1B[31m$str\x1B[0m");
    } else {
      print(str);
    }
  }
}

class LogWidget extends StatefulWidget {
  final double height;
  final Color? color;


  const LogWidget({Key? key, this.height = 200, this.color}) : super(key: key);

  @override
  State<LogWidget> createState() => _LogWidgetState();
}

class _LogWidgetState extends State<LogWidget> {
  final ScrollController scrollController = ScrollController();
  late Timer timer;
  bool exp = true;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    timer = Timer.periodic(const Duration(milliseconds: 300), (timer) {
      updateLog();
    });
  }

  @override
  void dispose() {
    // TODO: implement dispose
    timer.cancel();
    super.dispose();
  }

  updateLog() {
    //print("LogWidget: ${scrollController.offset}, max:${scrollController.position.maxScrollExtent}");
    if (!mounted) {
      return;
    }
    // if(scrollController.offset > 1 && scrollController.offset < (scrollController.position.maxScrollExtent - 50)){
    //   return;
    // }
    if (logUpdate) {
      toEnd();
    }
  }

  toEnd() {
    if(!exp){
      return;
    }
    Future.delayed(const Duration(milliseconds: 16)).then((value) =>
        scrollController.animateTo(scrollController.position.maxScrollExtent,
            duration: const Duration(milliseconds: 200),
            curve: Curves.easeOutQuart));
    logUpdate = false;
    if (mounted) {
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: exp?widget.height:60,
      color: widget.color ?? Colors.blue.withAlpha(40),
      padding: const EdgeInsets.only(left: 8,right: 8,top: 2,bottom: 2),
      width: double.infinity,
      alignment: Alignment.topLeft,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          exp ? Expanded(
              child: SingleChildScrollView(
                  controller: scrollController,
                  child: MyText(
                    logStr,
                    size: 10,
                    textAlign: TextAlign.start,
                    i18n: false,
                  ))):Container(),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              IconButton(
                  icon: const Icon(Icons.clear),
                  onPressed: () {
                    setState(() {
                      logStr = "";
                    });
                  }),
              IconButton(
                  icon: const Icon(Icons.vertical_align_bottom_outlined),
                  onPressed: () {
                    toEnd();
                  }),
              IconButton(
                  icon:  Icon(exp ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_up),
                  onPressed: () {
                    setState(() {
                      exp = !exp;
                    });
                  }),
            ],
          )
        ],
      ),
    );
  }
}
